package com.haifeng.asms.api.aop;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.haifeng.asms.api.annotation.FormRepeatableCommitAnnotation;
import com.haifeng.asms.commons.common.StatusCode;
import com.haifeng.asms.commons.exception.BusinessException;
import com.haifeng.asms.commons.utils.HostUtil;
import com.haifeng.asms.commons.utils.MessageUtil;
import com.haifeng.asms.commons.utils.RedisUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * <p>
 *  表单重复提交
 * </p>
 *
 * @author: Haifeng
 * @date: 2020-06-21
 */
@Slf4j
@Aspect
@Component
@AllArgsConstructor
public class FormRepeatableCommitAop implements Ordered {

    private final RedisUtil redisUtil;
    private final String username = "admin";
    private final MessageUtil messageUtil;

    /**
     * @param point
     */
    @Around("@annotation(com.haifeng.asms.api.annotation.FormRepeatableCommitAnnotation)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        HttpServletRequest request  = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ip = HostUtil.getIpAddress(request);
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //目标类、方法
        String uri = request.getRequestURI();
        FormRepeatableCommitAnnotation avoidRepeatableCommit =  method.getAnnotation(FormRepeatableCommitAnnotation.class);
        long intervalSecond = avoidRepeatableCommit.intervalSecond();
        String key = StrUtil.format("{}_{}_{}",uri,username,ip);
        if (redisUtil.hasKey(key)){
            throw new BusinessException(StatusCode.REQUEST_TOO_MANY, messageUtil.get(StatusCode.REQUEST_TOO_MANY));
        }
        redisUtil.setKeyWithExpire(key, UUID.fastUUID(),intervalSecond);
        //执行方法
        return point.proceed();
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
